package cn.csq.rpc.server;

import cn.csq.rpc.Request;
import cn.csq.rpc.Response;
import cn.csq.rpc.code.Decoder;
import cn.csq.rpc.code.Encoder;
import cn.csq.rpc.transport.RequestHandler;
import cn.csq.rpc.transport.TransportServer;
import com.csq.rpc.common.utils.ReflectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * rpc
 *
 * @author chengshanqing
 * @date Created in 2021/12/20 13:31
 */
@Slf4j
public class RpcServer {

    /**
     * 配置信息
     */
    private RpcServerConfig rpcServerConfig;

    /**
     * 网络通讯
     */
    private TransportServer net;

    /**
     * 序列化
     */
    private Encoder encoder;

    /**
     * 反序列化
     */
    private Decoder decoder;

    /**
     * 服务管理
     */
    private ServiceManager serviceManager;

    /**
     * 服务调用
     */
    private ServiceInvoker serviceInvoker;

    public RpcServer(RpcServerConfig rpcServerConfig) throws IllegalAccessException {
        this.rpcServerConfig = rpcServerConfig;
        //net
        this.net = ReflectionUtils.newInstance(rpcServerConfig.getTransportClass());
        this.net.init(rpcServerConfig.getPort(), this.handler);
        //encoder decoder
        this.encoder = ReflectionUtils.newInstance(rpcServerConfig.getEncoderClass());
        this.decoder = ReflectionUtils.newInstance(rpcServerConfig.getDecoderClass());
        //服务管理跟服务调用
        this.serviceManager = new ServiceManager();
        this.serviceInvoker = new ServiceInvoker();
    }

    public <T> void register(Class<T> instanceClass, T bean) {
        serviceManager.register(instanceClass, bean);
    }

    public void start() {
        //启动就是网络模块启动起来
        this.net.start();
    }

    public void stop() {
        this.net.close();
    }


    private RequestHandler handler = new RequestHandler() {
        @Override
        public void onRequest(InputStream recive, OutputStream toResp) {
            Response response = new Response();
            //读取请求的二进制数据
            try {
                byte[] bytes = IOUtils.readFully(recive, recive.available());
                Request request = decoder.decode(bytes, Request.class);
                log.info("get request:{}", request);
                //获取执行对象
                ServiceInstance lookup = serviceManager.lookup(request);
                //调用方法
                Object res = serviceInvoker.invoke(lookup, request);
                response.setData(res);
            } catch (IOException e) {
                log.error(e.getMessage(), e);
                response.setCode(1);
                response.setMessage("RpcServer got error:" + e.getClass().getName() + ":" + e.getMessage());
            }finally {
                //将方法返回值返回出去
                try {
                    byte[] encode = encoder.encode(response);
                    toResp.write(encode);
                    log.info("RpcServer response client:{}", response);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }

        }
    };
}
